package de.mmis.core.pojop.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.log4j.Logger;

import de.mmis.core.base.event.Observable;
import de.mmis.core.base.event.Observer;
import de.mmis.core.pojop.processor.RequestProcessorFactory;
import de.mmis.core.pojop.processor.RequestProcessorFactory.RequestProcessor;
import de.mmis.core.pojop.processor.RequestProcessorFactory.RequestProcessorEvent;
import de.mmis.core.pojop.request.HTTPRequest;

/**
 * implementation of the server interface providing a HTTP based communication
 * using S-Expressions intended to be used by web browsers and applications
 * 
 * @author Christian Koch
 * 
 */
public class HTTPServer extends AbstractServer<HTTPRequest> {

	private final static Logger LOGGER = Logger.getLogger(HTTPServer.class);

	public HTTPServer(int port,
			RequestProcessorFactory<HTTPRequest> requestProcessorFactory)
			throws IOException {
		super(port, requestProcessorFactory);
	}

	@Override
	public AbstractServer.SessionHandler createSessionHandler(Socket socket) {
		return new HTTPSessionHandler(socket,
				this.requestProcessorFactory.createRequestProcessor());
	}

	public class HTTPSessionHandler extends AbstractSessionHandler implements
			Observer<RequestProcessorEvent> {
		public HTTPSessionHandler(Socket socket,
				RequestProcessor<HTTPRequest> requestProcessor) {
			super(socket, requestProcessor);

			this.requestProcessor.addObserver(this);
		}

		@Override
		public HTTPRequest nextRequest() {

			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(
						this.instream, "UTF-8"));
				String requestLine;
				requestLine = br.readLine();
				if (requestLine == null) // nothing to do here, close connection
					return null;
				String[] requestLineParts = requestLine.split(" ");
				if (requestLineParts.length < 2) {
					String errorstring = "got invalid HTTP request: "
							+ requestLine;
					LOGGER.error(errorstring);
					return new HTTPRequest(new Exception(errorstring));
				}
				URI uri = new URI(requestLineParts[1]).normalize();
				return new HTTPRequest(uri);
			} catch (URISyntaxException e) {
				return new HTTPRequest(e);
			} catch (IOException e1) {
				LOGGER.error("IO error in client socket", e1);
				this.keepAnswering = false;
			}
			return null;
		}

		@Override
		public void notify(Observable<? extends RequestProcessorEvent> sender,
				RequestProcessorEvent event) {
			try {
				outwrite(event.getAnswer());
			} catch (IOException e) {
				LOGGER.error("IO error client socket", e);
				this.keepAnswering = false;
			}
		}

		@Override
		public String getConnectionTypeName() {
			return "HTTP";
		}
	}
}
